#!/usr/bin/env python
# encoding: utf-8


"""
@time: 2016/12/9 上午10:54
"""
from functools import reduce
from mathsolver.functions.base import *
from sympy import sympify, sqrt, FiniteSet, pi, acos, ImageSet, symbols, solveset
from mathsolver.functions.sanjiao.bianjiaozhuanhuan import (SIDES, ANGLES, JiaoHuaBian, sin, cos, tan, cancel, fraction,
                                                            simplify, expand_trig)
from itertools import chain
from mathsolver.functions.budengshi import common_opers as co
from operator import itemgetter
from mathsolver.functions.sanjiao import sanjiaoxing_utils as san_utils
from mathsolver.functions.sanjiao.sanjiaoxingqiuzhi import SanJiaoXingQiuZhi
from mathsolver.functions.sanjiao.triangle_constant import BASE_LINE_SUBS, TRIANGLE_SHAPR_SEARCH_KEY
from mathsolver.functions.sanjiao import sanjiaoxing_utils as sju
from mathsolver.functions.sanjiao.triangle_constant import TRIANGLE_NAME_SEARCH_KEY
from mathsolver.functions.sanjiao import sanjiao_utils as su
from collections import defaultdict

# cos角度的替换
COS_ANGLE_SUBS = (
    (cos(Symbol('A')), sympify('(b ** 2 + c ** 2 - a ** 2) / (2 * b * c)')),
    (cos(Symbol('B')), sympify('(a ** 2 + c ** 2 - b ** 2) / (2 * a * c)')),
    (cos(Symbol('C')), sympify('(a ** 2 + b ** 2 - c ** 2) / (2 * a * b)'))
)


# 三角形的一些实体

# 三角形
# 默认A, B, C代表三个角, a, b, c 代表角对应的边
class SanJiaoXing(object):
    def __init__(self, a='a', b='b', c='c', ja=None, jb=None, jc=None):
        self.a = sympify(a)
        self.BC_Side = sympify(a)
        self.b = sympify(b)
        self.AC_Side = sympify(b)
        self.c = sympify(c)
        self.AB_Side = sympify(c)
        self.A = ja
        self.B = jb
        self.C = jc
        self.eqs = []
        self.value = ''

    def center_line_length(self, side_name):
        """
        求边上中线的长度
        :param side_name: 边
        :return:
        """
        if str(side_name) == 'AC' or str(side_name) == 'b':
            return sqrt((self.c ** 2 + self.a ** 2 - self.b ** 2 / 2) / 2)
        elif str(side_name) == 'AB' or str(side_name) == 'c':
            return sqrt((self.b ** 2 + self.a ** 2 - self.c ** 2 / 2) / 2)
        elif str(side_name) == 'BC' or str(side_name) == 'a':
            return sqrt((self.c ** 2 + self.b ** 2 - self.a ** 2 / 2) / 2)
        else:
            raise Exception('cal error')

    def height(self, side_name):
        """
        求边上的高
        :param side_name:
        :return:
        """
        if str(side_name) == 'AC' or str(side_name) == 'b':
            return 2 * self.area() / self.b
        elif str(side_name) == 'AB' or str(side_name) == 'c':
            return 2 * self.area() / self.c
        elif str(side_name) == 'BC' or str(side_name) == 'a':
            return 2 * self.area() / self.a
        else:
            raise Exception('cal error')

    def center_line(self, side_name):
        """
        求某条边上的中线的长度
        :param side_name: 
        :return: 
        """
        side_name = str(sju.preprocess_base_triangle_expr(side_name))
        if side_name == 'a':  # a边上的中线
            return sqrt(2 * self.b ** 2 + 2 * self.c ** 2 - self.a ** 2) / 2
        elif side_name == 'b':
            return sqrt(2 * self.c ** 2 + 2 * self.a ** 2 - self.b ** 2) / 2
        elif side_name == 'c':
            return sqrt(2 * self.a ** 2 + 2 * self.b ** 2 - self.c ** 2) / 2
        else:
            raise Exception('Illegal side')

    def center_line_per_eq(self, first_c_l, second_c_l):
        """
        两条中线垂直的等价条件
        :param first_c_l:
        :param second_c_l:
        :return:
        """
        f = FiniteSet(first_c_l, second_c_l)
        if f == FiniteSet('A', 'B'):
            return BaseEq([5 * self.c ** 2, self.a ** 2 + self.b ** 2])
        elif f == FiniteSet('B', 'C'):
            return BaseEq([5 * self.a ** 2, self.b ** 2 + self.c ** 2])
        elif f == FiniteSet('A', 'C'):
            return BaseEq([5 * self.b ** 2, self.a ** 2 + self.c ** 2])
        else:
            raise Exception('caclute error')

    def area(self):
        """
        求面积
        :return:
        """
        s_v = sympify('sqrt(p*(p-a)*(p-b)*(p-c))')
        s_v = s_v.subs((('a', self.a), ('b', self.b), ('c', self.c)))
        s_v = simplify(s_v.subs('p', (self.a + self.b + self.c) / 2))
        return s_v

    def perimeter(self):
        """
        求周长
        :return:
        """
        return self.a + self.b + self.c

    def incircle_radius(self):
        """
        求内切圆半径
        :return:
        """
        return self.area() / self.perimeter()

    def update(self, cond):
        """
        更新三角形的条件
        :param cond:
        :return:
        """
        line_subs = (('BaseLine(AB)', 'c'), ('BaseLine(AC)', 'b'), ('BaseLine(BC)', 'a'))
        angle_subs = (('Angle(A)', 'A'), ('Angle(B)', 'B'), ('Angle(C)', 'C'))
        if isinstance(cond, BaseEq):
            eq_l, eq_r = cond.sympify()
            eq_l = eq_l.subs(line_subs).subs(angle_subs)
            eq_r = eq_r.subs(line_subs).subs(angle_subs)
            self.eqs.append([eq_l, eq_r])

    @staticmethod
    def simu_trian_eqs(eqs):
        """
        转换各种等式, 输出一个或多个方程组
        :param eqs:
        :return:
        """
        eq_list = []  # 存储那些根据条件 只能得出一个等式[元素里面每个元素的类型为 BaseEq]
        eqs_list = []  # 存储那些根据条件 得出多个等式  [元素里面每个元素的类型为 BaseEqs]
        du_p = r'du(\(\d+?\))'
        lines_subs = (('AB', 'c'), ('AC', 'b'), ('BC', 'a'))
        for l_expr, r_expr in eqs.sympify():
            tmp_f = l_expr - r_expr
            tmp_f = tmp_f.subs(lines_subs).subs(BASE_LINE_SUBS)
            _m = re.search(du_p, str(tmp_f))
            if _m:
                du_str = _m.group()
                du_sub = sympify(_m.groups()[0]) * pi / 180
                tmp_f = tmp_f.subs(du_str, du_sub)
            tmp_f = expand_trig(tmp_f)  # 2017-03-28添加
            symbs = list(tmp_f.free_symbols)
            if len(symbs) == 1:  # 如果只含有一个未知变量
                symb = symbs[0]
                if su.i_is_subset(symb, SIDES):  # 如果是边的变量 old: FiniteSet(symb).is_subset(SIDES)
                    eq_list.append([tmp_f, '0'])
                elif su.i_is_subset(symb, ANGLES):  # 如果是角的变量 old: FiniteSet(symb).is_subset(ANGLES)
                    symb_value = solveset(tmp_f)
                    # if isinstance(symb_value, ImageSet):  # 当 出现 sin(A) = 1/2的时候 解是 ImageSet,此时应该做些变换
                    #     pass
                    if isinstance(symb_value, FiniteSet):  # 如果是类似 A = pi/4
                        v = list(symb_value)[0]
                        eq_list.append([(cos(symb) - cos(v)).subs(COS_ANGLE_SUBS), '0'])
                    elif isinstance(symb_value, ImageSet):  # 角的一个三角等式 形如 sin(A) + cos(A) = 1
                        angle_trig_values_list = su.trig_func_values(BaseEq([tmp_f, 0]))  # 根据一个等式 得出其他三角函数值
                        _eqs = []
                        for _values in angle_trig_values_list:
                            _m = dict(_values)
                            cos_v = _m[cos(symb)]
                            _eqs.append([(cos(symb) - cos_v).subs(COS_ANGLE_SUBS), '0'])
                        eqs_list.append(BaseEqs(_eqs))
                    else:
                        tmp_f = tmp_f.subs(COS_ANGLE_SUBS)
                        if tmp_f.coeff(sin(symb)):  # 如果含有sin的
                            eqs2 = []
                            sin_symb_value = solve(tmp_f, sin(symb))[0]
                            cos_symb_value = sqrt(1 - sin_symb_value ** 2)  # sqrt(1-sin(A)**2)
                            eqs2.append([(cos(symb) - cos_symb_value).subs(COS_ANGLE_SUBS), '0'])
                            cos_symb_value = -sqrt(1 - sin_symb_value ** 2)  # -sqrt(1-sin(A)**2)
                            eqs2.append([(cos(symb) - cos_symb_value).subs(COS_ANGLE_SUBS), '0'])
                            eqs_list.append(BaseEqs(eqs2))
                        elif tmp_f.coeff(tan(symb)):  # 如果含有tan的
                            tan_symb_value = solve(tmp_f, tan(symb))[0]
                            sin_cos_values = solve(
                                (tan_symb_value * cos(symb) - sin(symb), sin(symb) ** 2 + cos(symb) ** 2 - 1),
                                sin(symb), cos(symb))
                            cos_values = map(lambda _: _[cos(symb)], sin_cos_values)
                            tmp_eqs = map(lambda cv: [(cv - cos(symb)).subs(COS_ANGLE_SUBS), '0'], cos_values)
                            eqs_list.append(BaseEqs(tmp_eqs))
                        else:
                            eq_list.append([tmp_f, 0])
                else:
                    eqs_list.append(JiaoHuaBian(verbose=True).solver(BaseEq([tmp_f, '0'])).output[0])
            elif su.i_is_subset(symbs, SIDES):  # old FiniteSet(*symbs).is_subset(SIDES)
                eq_list.append([tmp_f, '0'])
            elif len(symbs) == 2 and su.i_is_subset(symbs, ANGLES) and not su.is_trig_f(
                    tmp_f):  # 如果只是存的角的关系 那么就需要做一些变换。比如 B = 2A
                a1, a2 = symbs
                a1_v = solve(tmp_f, a1)[0]
                if a1_v.coeff(a1) in S.Integers:
                    _eq = [sin(a1), expand_trig(sin(a1_v))]
                    eqs_list.append(JiaoHuaBian(verbose=True).solver(BaseEq(_eq)).output[0])
                else:
                    a2_v = solve(tmp_f, a2)[0]
                    _eq = [sin(a2), expand_trig(sin(a2_v))]
                    eqs_list.append(JiaoHuaBian(verbose=True).solver(BaseEq(_eq)).output[0])

            else:
                eqs_list.append(JiaoHuaBian(verbose=True).solver(BaseEq([tmp_f, '0'])).output[0])
        eq_list = list(map(lambda _: [co.complete_fraction(cancel(sympify(_[0]) - sympify(_[1])))[0], 0], eq_list))
        result_base_eqs_list = []
        if eqs_list:
            base_eqs = BaseEqs(eq_list)
            eqs_list = map(lambda _: _.sympify(), eqs_list)
            target_eq_sets_list = co.combin_iters((base_eqs,), *eqs_list)  # 目标方程组可能的列表
            for eq_sets in target_eq_sets_list:
                first_eqs = eq_sets[0].sympify()
                tmp_eq_sets = list(chain(first_eqs, eq_sets[1:]))
                tmp_eq_sets = map(lambda _: [fraction(cancel(sympify(_[0]) - sympify(_[1])))[0], 0], tmp_eq_sets)
                result_base_eqs_list.append(BaseEqs(tmp_eq_sets))
        else:
            result_base_eqs_list.append(BaseEqs(eq_list))
        return result_base_eqs_list

    def process_conds(self, eqs):
        base_eqs_list = SanJiaoXing.simu_trian_eqs(eqs)
        abc_values_list = []
        for base_eqs in base_eqs_list:
            try:
                abc_values = co.solve_poly_eqs(base_eqs)
                abc_values_list.extend(abc_values)
            except Exception:
                pass
        # 合法的边
        abc_values_list = filter(
            lambda _: san_utils.legal_sided(_[0][1]) and san_utils.legal_sided(_[1][1]) and san_utils.legal_sided(
                _[2][1]), abc_values_list)
        # 是否满足两边之和大于第三边
        abc_values_list = filter(lambda _: san_utils.legal_sides((_[0][1], _[1][1], _[2][1])), abc_values_list)
        for abc_values in abc_values_list:
            cos_a_v = sympify('(b**2 + c**2 - a**2)/(2*b*c)').subs(abc_values)
            cos_b_v = sympify('(a**2 + c**2 - b**2)/(2*a*c)').subs(abc_values)
            cos_c_v = sympify('(a**2 + b**2 - c**2)/(2*a*b)').subs(abc_values)
            angle_a = acos(cos_a_v)
            angle_b = acos(cos_b_v)
            angle_c = acos(cos_c_v)
            self.a, self.b, self.c = map(itemgetter(1), abc_values)
            self.A, self.B, self.C = angle_a, angle_b, angle_c


# 解三角形 1 如果有三个条件 则求出三条边； 2 如果小于三个条件 则根据条件和问题推导出要求的值
# Input1 paramer1: BaseEqs 已知条件方程组; paramer2: 问题表达式
# Input2 paramer1: 问题表达式 使用self.search 搜寻已知的条件
# Input3 paramer1: BaseEqs 已知条件方程组 此时返回求出的a, b, c三条边的值
# Input3 没有参数 如果可以search出已知条件则 返回 a, b, c, 三['b', '2*sin(B)*r']条边的值
class JieSanJiaoXing(BaseFunction):
    # 知道 r的值 可以算出 (a+b+c)/(sin(A) + sin(B) + sin(C))的值
    def _solver1(self, *args):
        self.label.add('解三角形')
        self.label.add('正弦定理')
        eqs = args[0]
        target_f = args[1].sympify()
        r_value = None
        for eq in eqs.sympify():
            eq_f = eq[0] - eq[1]
            symbs = list(eq_f.free_symbols)
            if len(symbs) == 2 and abs(ord(str(symbs[0])) - ord(str(symbs[1]))) == 32:
                angle, side = sorted(symbs, key=str)
                sin_value = solve(eq_f, sin(angle))[0]
                if sin_value.subs(side, 0) == 0:
                    r_value = side / (2 * sin_value)
        if r_value:  # 知道r的值
            a_value = 2 * r_value * sin('A')
            b_value = 2 * r_value * sin('B')
            c_value = 2 * r_value * sin('C')
            self.steps.append(['由题意可知:', BaseEqs([['a', a_value], ['b', b_value], ['c', c_value]]).printing()])
            f_value = simplify(target_f.subs((('a', a_value), ('b', b_value), ('c', c_value))))
            if not f_value.is_real:
                raise Exception('Type Match Error')
            self.steps.append(['所以', new_latex(target_f) + '=' + new_latex(f_value)])
            self.output.append(BaseNumber(f_value))
        else:
            raise Exception('Type Match Error')
        return self

    def old_solver(self, *args):
        self.label.add('解三角形')
        line_subs = sju.get_triangle_line_subs()
        question_angle_subs = (('Angle(A)', 'acos(cos(A))'), ('Angle(B)', 'acos(cos(B))'), ('Angle(C)', 'acos(cos(C))'),
                               ('Angle(B, A, C)', 'acos(cos(A))'), ('Angle(C, A, B)', 'acos(cos(A))'),
                               ('Angle(A, B, C)', 'acos(cos(B))'), ('Angle(C, B, A)', 'acos(cos(B))'),
                               ('Angle(A, C, B)', 'acos(cos(C))'), ('Angle(B, C, A)', 'acos(cos(C))')
                               )
        arg = args[0]
        tmp_eqs = san_utils.known_triangle_eqs(self.known)
        if isinstance(arg, BaseEqs):
            eqs = arg
        elif isinstance(tmp_eqs, BaseEqs):
            eqs = tmp_eqs
        else:
            raise Exception('Illegal parameters')
        eqs_list = eqs.sympify()
        new_eqs = []
        for tmp_eq in eqs_list:
            e_l, e_r = tmp_eq
            # e_l = e_l.subs(line_subs).subs(SanJiaoXingLineSubs)
            e_l = e_l.subs(sju.get_triangle_subs())
            # e_r = e_r.subs(line_subs).subs(SanJiaoXingLineSubs)
            e_r = e_r.subs(sju.get_triangle_subs())
            new_eqs.append([e_l, e_r])
        new_eqs = BaseEqs(new_eqs)
        if len(new_eqs.sympify()) < 3:
            if (isinstance(args[0], BaseEqs) or isinstance(args[0], BaseEq)) and isinstance(args[1], BasePoly):
                return SanJiaoXingQiuZhi(verbose=True).solver(new_eqs, args[1])
            else:
                arg_f = arg.sympify()
                arg_f = arg_f.subs(sju.get_triangle_subs())
                return SanJiaoXingQiuZhi(verbose=True).solver(new_eqs, BasePoly(arg_f))
        eq_sets = SanJiaoXing.simu_trian_eqs(new_eqs)  # 联立方程组
        abc_values_list = []
        self.label.add('边角转换')
        self.steps.append(['由题意可利用边角转换得到方程组:', ''])
        for base_eqs in eq_sets:
            self.steps.append(['得:', base_eqs.printing()])
            try:
                # old: abc_values = co.solve_poly_eqs(base_eqs)
                abc_values = co.isolve_eqs(base_eqs, ['a', 'b', 'c'])
                self.steps.append(['求得:', ''])
                if abc_values:  # 有可能解出来是空集
                    _i = 1
                    for tmp_set in abc_values:
                        if _i == 1:
                            self.steps.append(['', BaseEqs(tmp_set).printing()])
                        else:
                            self.steps.append(['', '或'])
                            self.steps.append(['', BaseEqs(tmp_set).printing()])
                        _i += 1
                    abc_values_list.extend(abc_values)
            except Exception:
                pass
        # 合法的边
        abc_values_list = filter(
            lambda _: san_utils.legal_sided(_[0][1]) and san_utils.legal_sided(_[1][1]) and san_utils.legal_sided(
                _[2][1]), abc_values_list)
        # 是否满足两边之和大于第三边
        abc_values_list = filter(lambda _: san_utils.legal_sides((_[0][1], _[1][1], _[2][1])), abc_values_list)
        # 锐角三角形，钝角三角形 等等条件
        if self.search(TRIANGLE_SHAPR_SEARCH_KEY):
            triangle_type = str(list(self.search(TRIANGLE_SHAPR_SEARCH_KEY))[0])
            if triangle_type == 'acute_triangle':  # 锐角三角形
                abc_values_list = filter(lambda _: san_utils.acute_triangled((_[0][1], _[1][1], _[2][1])),
                                         abc_values_list)
            elif triangle_type == 'obtuse_triangle':  # 钝角三角形
                abc_values_list = filter(lambda _: san_utils.obtuse_triangled((_[0][1], _[1][1], _[2][1])),
                                         abc_values_list)
        a_vs, b_vs, c_vs = [], [], []
        self.steps.append(['根据已知条件和三角关系验证求得:', ''])
        _i = 1
        for abc_values in abc_values_list:
            a_v, b_v, c_v = abc_values[0:3]
            if _i == 1:
                self.steps.append([BaseEqs(abc_values).printing(), ''])
            else:
                self.steps.append(['或', ''])
                self.steps.append([BaseEqs(abc_values).printing(), ''])
            a_vs.append(a_v[1])
            b_vs.append(b_v[1])
            c_vs.append(c_v[1])
            _i += 1
        if len(args) == 2 and isinstance(args[0], BaseEqs):  # Input1
            target_f = expand_trig(args[1].sympify())
        elif isinstance(args[0], BaseEqs) and len(args) == 1:  # Input3
            self.output.append(BaseSymbolValue({'a': a_vs}))
            self.output.append(BaseSymbolValue({'b': b_vs}))
            self.output.append(BaseSymbolValue({'c': c_vs}))
            return self
        elif len(args) == 1:  # Input2
            target_f = expand_trig(arg.sympify())
        else:
            raise Exception('Type Match Error')
        # target_f = expand_trig(arg.sympify())
        if target_f == sympify('l'):  # 求周长
            target_f = sympify('a+b+c')
        target_f_vs = []
        known_values = defaultdict(list)
        _a, _b, _c = symbols('a, b, c')
        __a, __b, __c = symbols('A, B, C')
        for a_v, b_v, c_v in zip(a_vs, b_vs, c_vs):
            known_values[_a].append(a_v)
            known_values[_b].append(b_v)
            known_values[_c].append(c_v)
            a_b_c_subs = (('a', a_v), ('b', b_v), ('c', c_v))
            side_values = (('a', a_v), ('b', b_v), ('c', c_v))
            cos__a = san_utils.triangle_angle_cos(side_values, 'A')
            known_values[cos(__a)].append(cos__a)
            sin__a = sqrt(1 - cos__a ** 2)
            known_values[sin(__a)].append(sin__a)
            tan__a = sin__a / cos__a
            known_values[tan(__a)].append(tan__a)
            cos__b = san_utils.triangle_angle_cos(side_values, 'B')
            known_values[cos(__b)].append(cos__b)
            sin__b = sqrt(1 - cos__b ** 2)
            known_values[sin(__b)].append(sin__b)
            tan__b = sin__b / cos__b
            known_values[tan(__b)].append(tan__b)
            cos__c = san_utils.triangle_angle_cos(side_values, 'C')
            known_values[cos(__c)].append(cos__c)
            sin__c = sqrt(1 - cos__c ** 2)
            known_values[sin(__c)].append(sin__c)
            tan__c = sin__c / cos__c
            known_values[tan(__c)].append(tan__c)
            # 最后一步 还要验证 是否满足给定的等式，有发现求出来的结果 满足三角形条件 但是不满足等式的【一般是特殊角】
            _A = acos(cos__a)
            _B = acos(cos__b)
            _C = acos(cos__c)
            if su.i_is_subset({_A, _B, _C}, {pi / 6, pi / 4, pi / 3, pi / 2, 2 * pi / 3, pi}):  # 特殊角就算出来
                known_values[__a].append(_A)
                known_values[__b].append(_B)
                known_values[__c].append(_C)
                if _A + _B + _C != pi:
                    continue
                # 验证是否满足 角的关系
                _angle_subs = (('A', _A), ('B', _B), ('C', _C))
                angle_eqs = list(filter(lambda _: sympify(str(_[0])).subs(_angle_subs).is_real and sympify(str(_[1])).subs(_angle_subs).is_real, new_eqs.sympify()))
                if angle_eqs:
                    angle_eqs2 = list(filter(lambda _: sympify(str(_[0])).subs(_angle_subs) == sympify(str(_[1])).subs(_angle_subs), angle_eqs))
                    if len(angle_eqs2) != len(angle_eqs):
                        continue
            target_f_v = target_f.subs(BASE_LINE_SUBS).subs(line_subs).subs(a_b_c_subs).subs(question_angle_subs).subs(
                (('cos(A)', cos__a), ('sin(A)', sin__a), ('tan(A)', tan__a), ('A', acos(cos__a)),
                 ('cos(B)', cos__b), ('sin(B)', sin__b), ('tan(B)', tan__b), ('B', acos(cos__b)),
                 ('cos(C)', cos__c), ('sin(C)', sin__c), ('tan(C)', tan__c), ('C', acos(cos__c))))
            target_f_vs.append(simplify(target_f_v))
        target_f_vs_print = reduce(lambda _1, _2: _1 + ' 或 ' + _2, map(lambda _: new_latex(_), target_f_vs))
        self.steps.append(['求得 %s值 为' % new_latex(target_f), target_f_vs_print])
        # self.output.append(BaseSymbolValue({target_f: target_f_vs}))
        self.output.append(BaseSymbolValue(known_values))
        return self

    def solver2(self, *args):
        """
        解决复合多三角形问题
        :param args: 
        :return: 
        """
        self.label.add('解三角形')
        triangle_obj = self.search(TRIANGLE_NAME_SEARCH_KEY)
        triangle_result = triangle_obj.solve_triangle()
        _values = triangle_obj.solve_all_values()
        # for lable in triangle_result.labels:
        #     self.label.add(lable)
        self.steps.extend(triangle_obj.get_steps())
        self.steps.append(['得:', BaseEqs(triangle_result).printing()])
        q = args[0]
        if isinstance(q, BaseLine):  # 求边长
            line = sympify(''.join(q.value))
            line_value = line.subs(_values)
            self.steps.append(['所以', new_latex(line) + '=' + new_latex(line_value)])
        else:
            q_f = q.sympify().subs(sju.get_triangle_subs())
            f_v = q_f.subs(_values)
            self.steps.append(['所以求得:', new_latex(q_f) + '=' + new_latex(f_v)])
        return self

    def solver(self, *args):
        solvers = [self._solver1, self.old_solver, self.solver2]
        result = None
        for sl in solvers:
            try:
                result = sl(*args)
                break
            except Exception:
                pass
        if not result:
            raise Exception('Try Error')
        return result


if __name__ == '__main__':
    pass
